﻿using System;
using System.Collections.Generic;
using System.Web;
using System.Xml;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.member;
using umbraco.presentation.nodeFactory;

namespace uForum.Businesslogic
{

	/// <summary>
	/// Strictly a helper class for making the code a bit more transparent
	/// It simply combines info from NodeFactory (forum info) and the custom Topic / Comment tables
	/// </summary>
	public class Forum
	{
		public int Id { get; set; }
		public int ParentId { get; set; }

		public string Title { get; private set; }
		public string Description { get; set; }
		public DateTime LatestPostDate { get; set; }
		public bool Exists { get; private set; }

		public int TotalTopics { get; set; }
		public int TotalComments { get; set; }
		public int SortOrder { get; set; }

		public Comment LatestComment
		{
			get
			{
				if (_latestCommentID > 0)
				{
					try
					{
						return new Comment(_latestCommentID);
					}
					catch (ArgumentException ex)
					{
						Log.Add(LogTypes.Error, 0, ex.Message);
					}
				}
				return null;
			}
		}
		public Topic LatestTopic
		{
			get
			{
				if (_latestTopicID > 0)
				{
					try
					{
						return new Topic(_latestTopicID);
					}
					catch (ArgumentException ex)
					{
						Log.Add(LogTypes.Error, 0, ex.Message);
					}

				}
				return null;
			}
		}

		private int _latestCommentID;
		private int _latestTopicID;
		private string _latestAuthorID;

		public List<Forum> SubForums { get; set; }

		private Events _e = new Events();

		public Forum() { }


		public static Forum Create(int forumId, int parentId, int sortOrder)
		{
			Forum f = new Forum
			              {
			                  Id = forumId, 
                              ParentId = parentId, 
                              SortOrder = sortOrder, 
                              Exists = false
			              };
		    f.Save();
			return f;
		}

		public void Delete()
		{

			Data.SqlHelper.ExecuteNonQuery("DELETE FROM forumForums where ID = @id",
						Data.SqlHelper.CreateParameter("@id", Id));

		}

		public void Save()
		{
			if (!Exists)
			{

				CreateEventArgs e = new CreateEventArgs();
				FireBeforeCreate(e);
				if (!e.Cancel)
				{
					Data.SqlHelper.ExecuteNonQuery("INSERT INTO forumForums (id, parentId, sortOrder) VALUES(@id, @parentId, @sortOrder)",
					Data.SqlHelper.CreateParameter("@id", Id), Data.SqlHelper.CreateParameter("@parentId", ParentId), Data.SqlHelper.CreateParameter("@sortOrder", SortOrder)
					);

					FireAfterCreate(e);
				}
			}
			else
			{

				UpdateEventArgs e = new UpdateEventArgs();
				FireBeforeUpdate(e);

				if (!e.Cancel)
				{

					TotalTopics = Data.SqlHelper.ExecuteScalar<int>("SELECT count(*) from forumTopics where parentId = @id", Data.SqlHelper.CreateParameter("@id", Id));
					TotalComments = Data.SqlHelper.ExecuteScalar<int>("SELECT COUNT(forumComments.id) FROM forumTopics INNER JOIN forumComments ON forumComments.topicId = forumTopics.id WHERE (forumTopics.parentId = @id)", Data.SqlHelper.CreateParameter("@id", Id));

					if (TotalTopics > 0)
					{
						_latestTopicID = Data.SqlHelper.ExecuteScalar<int>("SELECT TOP 1 id FROM forumTopics WHERE (forumTopics.parentId = @id) ORDER BY Updated DESC ", Data.SqlHelper.CreateParameter("@id", Id));
						_latestAuthorID = Data.SqlHelper.ExecuteScalar<string>("SELECT TOP 1 latestReplyAuthor FROM forumTopics WHERE (forumTopics.parentId = @id) ORDER BY Updated DESC ", Data.SqlHelper.CreateParameter("@id", Id));
						LatestPostDate = Data.SqlHelper.ExecuteScalar<DateTime>("SELECT TOP 1 updated FROM forumTopics WHERE (forumTopics.parentId = @id) ORDER BY Updated DESC", Data.SqlHelper.CreateParameter("@id", Id));

						if (TotalComments > 0)
						{
							_latestCommentID = Data.SqlHelper.ExecuteScalar<int>("SELECT TOP 1 id FROM forumComments WHERE (topicId = @id) ORDER BY Created DESC ", Data.SqlHelper.CreateParameter("@id", _latestTopicID));
						}
					}



					Data.SqlHelper.ExecuteNonQuery(@"UPDATE forumForums 
                        SET latestComment = @latestComment, latestTopic = @latestTopic, 
                        latestAuthor = @latestAuthor, totalTopics = @totalTopics, 
                        totalComments = @totalComments, latestPostDate = @latestPostDate,
                        sortOrder = @sortOrder
                        WHERE id = @id",
						Data.SqlHelper.CreateParameter("@latestComment", _latestCommentID),
						Data.SqlHelper.CreateParameter("@latestTopic", _latestTopicID),
						Data.SqlHelper.CreateParameter("@latestAuthor", _latestAuthorID),
						Data.SqlHelper.CreateParameter("@totalTopics", TotalTopics),
						Data.SqlHelper.CreateParameter("@totalComments", TotalComments),
						Data.SqlHelper.CreateParameter("@latestPostDate", LatestPostDate),
						Data.SqlHelper.CreateParameter("@sortOrder", SortOrder),
						Data.SqlHelper.CreateParameter("@id", Id)
						);
					FireAfterUpdate(e);
				}
			}
		}


		public void SetLatestTopic(int topicId)
		{
			_latestTopicID = topicId;
		}

		public void SetLatestComment(int commentId)
		{
			_latestCommentID = commentId;
		}

		public void SetLatestAuthor(string Id)
		{
			_latestAuthorID = Id;
		}

		public Forum(int forumID)
		{
			umbraco.DataLayer.IRecordsReader dr = Data.SqlHelper.ExecuteReader("SELECT * FROM forumForums WHERE ID = @id", Data.SqlHelper.CreateParameter("@id", forumID));

			if (dr.Read())
			{
				Node n = new Node(dr.GetInt("id"));

				Forum f = new Forum();
				Id = dr.GetInt("id");
				Title = n.Name;
				Description = n.GetProperty("forumDescription").Value;
				Exists = true;
				TotalComments = dr.GetInt("totalComments");
				TotalTopics = dr.GetInt("totalTopics");

				//Latest private vals
				_latestAuthorID = dr.GetString("latestAuthor");
				_latestCommentID = dr.GetInt("latestComment");
				_latestTopicID = dr.GetInt("latestTopic");
				LatestPostDate = dr.GetDateTime("latestPostDate");
			}
			else
				Exists = false;
		}

		public static List<Forum> Forums() { return Forums(0); }
		public static List<Forum> Forums(int parentId)
		{

			List<Forum> lt = new List<Forum>();

			umbraco.DataLayer.IRecordsReader dr;

			if (parentId > 0)
			{
				dr = Data.SqlHelper.ExecuteReader(
					"SELECT * FROM forumForums WHERE parentID = @parentId ORDER by sortOrder ASC", Data.SqlHelper.CreateParameter("@parentId", parentId)
				);
			}
			else
			{
				dr = Data.SqlHelper.ExecuteReader(
					"SELECT * FROM forumForums ORDER by sortOrder ASC"
				);
			}

			while (dr.Read())
			{
				Node n = new Node(dr.GetInt("id"));
				if (n.Id != 0)
				{

					Forum f = new Forum();
					f.Id = dr.GetInt("id");
					f.ParentId = dr.GetInt("parentId");
					f.Title = n.Name;
					f.Description = n.GetProperty("forumDescription").Value;
					f.Exists = true;
					f.SortOrder = dr.GetInt("SortOrder");

					//Latest private vals
					f._latestAuthorID = dr.GetString("latestAuthor");
					f._latestCommentID = dr.GetInt("latestComment");
					f._latestTopicID = dr.GetInt("latestTopic");

					f.LatestPostDate = dr.GetDateTime("latestPostDate");
					f.TotalComments = dr.GetInt("totalComments");
					f.TotalTopics = dr.GetInt("totalTopics");

					lt.Add(f);
				}
			}

			return lt;
		}

		public XmlNode ToXml(XmlDocument d, bool includeLatestData)
		{
			XmlNode tx = d.CreateElement("forum");

			tx.AppendChild(umbraco.xmlHelper.addTextNode(d, "title", Title));
			tx.AppendChild(umbraco.xmlHelper.addCDataNode(d, "description", Description));

			tx.Attributes.Append(umbraco.xmlHelper.addAttribute(d, "id", Id.ToString()));
			tx.Attributes.Append(umbraco.xmlHelper.addAttribute(d, "LatestTopic", _latestTopicID.ToString()));
			tx.Attributes.Append(umbraco.xmlHelper.addAttribute(d, "LatestComment", _latestCommentID.ToString()));
			tx.Attributes.Append(umbraco.xmlHelper.addAttribute(d, "LatestAuthor", _latestAuthorID.ToString()));
			tx.Attributes.Append(umbraco.xmlHelper.addAttribute(d, "SortOrder", SortOrder.ToString()));

			tx.Attributes.Append(umbraco.xmlHelper.addAttribute(d, "TotalTopics", TotalTopics.ToString()));
			tx.Attributes.Append(umbraco.xmlHelper.addAttribute(d, "TotalComments", TotalComments.ToString()));

			tx.Attributes.Append(umbraco.xmlHelper.addAttribute(d, "LatestPostDate", LatestPostDate.ToString("s")));

			//if it's not needed you can save some db queries... 
			if (includeLatestData)
			{
				//add latest data as xml
				XmlNode l = umbraco.xmlHelper.addTextNode(d, "latest", "");

				//if (!string.IsNullOrEmpty(_latestAuthorID)
				//    l.AppendChild(MemberToXml(_latestAuthorID, d));

				if (_latestCommentID > 0 && LatestComment != null)
					l.AppendChild(LatestComment.ToXml(d));

				if (_latestTopicID > 0 && LatestTopic != null)
					l.AppendChild(LatestTopic.ToXml(d));

				tx.AppendChild(l);
			}

			return tx;

		}



		/* Events */
		public static event EventHandler<CreateEventArgs> BeforeCreate;
		protected virtual void FireBeforeCreate(CreateEventArgs e)
		{
			_e.FireCancelableEvent(BeforeCreate, this, e);
		}
		public static event EventHandler<CreateEventArgs> AfterCreate;
		protected virtual void FireAfterCreate(CreateEventArgs e)
		{
			if (AfterCreate != null)
				AfterCreate(this, e);
		}

		public static event EventHandler<DeleteEventArgs> BeforeDelete;
		protected virtual void FireBeforeDelete(DeleteEventArgs e)
		{
			_e.FireCancelableEvent(BeforeDelete, this, e);
		}
		public static event EventHandler<DeleteEventArgs> AfterDelete;
		protected virtual void FireAfterDelete(DeleteEventArgs e)
		{
			if (AfterDelete != null)
				AfterDelete(this, e);
		}

		public static event EventHandler<UpdateEventArgs> BeforeUpdate;
		protected virtual void FireBeforeUpdate(UpdateEventArgs e)
		{
			_e.FireCancelableEvent(BeforeUpdate, this, e);
		}
		public static event EventHandler<UpdateEventArgs> AfterUpdate;
		protected virtual void FireAfterUpdate(UpdateEventArgs e)
		{
			if (AfterUpdate != null)
				AfterUpdate(this, e);
		}

	}
}